16

I read this post about card shuffling and in many shuffling and sorting algorithms you need to swap two items in a list or array. But what does a good and efficient Swap method look like?

Let's say for a T[] and for a List<T>. How would you best implement a method that swaps two items in those two?

Swap(ref cards[i], ref cards[n]); // How is Swap implemented? 

7 Answers 7

29

Well, the code you have posted (ref cards[n]) can only work with an array (not a list) - but you would use simply (where foo and bar are the two values):

static void Swap(ref int foo, ref int bar) { int tmp = foo; foo = bar; bar = tmp; } 

Or possibly (if you want atomic):

Interlocked.Exchange(ref foo, ref bar); 

Personally, I don't think I'd bother with a swap method, though - just do it directly; this means that you can use (either for a list or for an array):

int tmp = cards[n]; cards[n] = cards[i]; cards[i] = tmp; 

If you really wanted to write a swap method that worked on either a list or an array, you'd have to do something like:

static void Swap(IList<int> list, int indexA, int indexB) { int tmp = list[indexA]; list[indexA] = list[indexB]; list[indexB] = tmp; } 

(it would be trivial to make this generic) - however, the original "inline" version (i.e. not a method) working on an array will be faster.

Sign up to request clarification or add additional context in comments.

8 Comments

Re the array - you aren't passing the array - you are passing the element.
If these are integers, wouldn't it be better to just swap by value?
The int was just meant as an example though. should probably clear that up in the question...
I assume the JIT compiler will inline the generic swap so I see no performance reason to choose for the 'inline' method instead of the generic extension.
I know this is a very old question, but could you perhaps elaborate on why the generic method would be slower than the inline version? Is this still accurate?
|
6

11 years later and we have tuples...

(foo, bar) = (bar, foo); 

3 Comments

Welcome to SO, @gaggleweed, and thanks for the good contribution! One note: The OP asked for the swap functionality to be buried within a method, but your code does the swap directly inline. I can see why it would seem unnecessary to put such a simple one-liner in a method, but it would be good to explain that in the post if that's what you were thinking. Or better yet, explain that and include a version that has it in a method, just in case the OP has a good reason for wanting it that way.
It's also worth noting that this is not thread-safe, but that would only matter if you were swapping variables that are shared beyond the local scope.
Despite it's elegant one-liner, I would pass benchmark before using it.
3

A good swap is one where you don't swap the contents. In C/C++ this would be akin to swapping pointers instead of swapping the contents. This style of swapping is fast and comes with some exception guarantee. Unfortunately, my C# is too rusty to allow me to put it in code. For simple data types, this style doesn't give you much. But once you are used to, and have to deal with larger (and more complicated) objects, it can save your life.

1 Comment

But for an int[] or List<int>, the contents are either the same (x86) or half the size (x64). In this case, swap the contents.
3

What about this? It's a generic implementation of a swap method. The Jit will create a compiled version ONLY for you closed types so you don't have to worry about perfomances!

/// <summary> /// Swap two elements /// Generic implementation by LMF /// </summary> public static void Swap<T>(ref T itemLeft, ref T itemRight) { T dummyItem = itemRight; itemLeft = itemRight; itemRight = dummyItem; } 

HTH Lorenzo

Comments

2

Use:

void swap(int &a, int &b) { // &a != &b // a == b OK a ^= b; b ^= a; a ^= b; return; } 

I did not realize I was in the C# section. This is C++ code, but it should have the same basic idea. I believe ^ is XOR in C# as well. It looks like instead of & you may need "ref"(?). I am not sure.

8 Comments

Interesting... what do those comments mean?
(And is that return; really needed?)
return is not needed, and you would use ref instead of & yes, +1
FWIW, Wikipedia claims that this method is actually less efficient than the usual buffer = a; a = b; b = buffer; construct.
Benchmarks show that indeed temp variable swap is faster than 3 XOR operations in C#.
|
0

You can now use tuples to accomplish this swap without having to manually declare a temporary variable:

static void Swap<T>(ref T foo, ref T bar) { (foo, bar) = (bar, foo) } 

Comments

-1

For anyone wondering, swapping can also be done also with Extension methods (.NET 3.0 and newer).

In general there seems not to be possibility to say that extension methods "this" value is ref, so you need to return it and override the old value.

public static class GeneralExtensions { public static T SwapWith<T>(this T current, ref T other) { T tmpOther = other; other = current; return tmpOther; } } 

This extension method can be then used like this:

int val1 = 10; int val2 = 20; val1 = val1.SwapWith(ref val2); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.